﻿using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;

public class Person : INotifyPropertyChanged
{
    private string _firstName;
    private string _lastName;

    public event PropertyChangedEventHandler PropertyChanged;

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName != value)
            {
                _firstName = value;
                FirePropertyChanged("FirstName");
            }
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            if (_lastName != value)
            {
                _lastName = value;
                FirePropertyChanged("LastName");
            }
        }
    }

    private void FirePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class Person_StaticReflection : NotifyPropertyChanged
{
    private string _firstName;
    private string _lastName;

    public string FirstName
    {
        get { return _firstName; }
        set { SetProperty(() => FirstName, () => _firstName, value); }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            SetProperty(() => LastName, () => _lastName, value, () =>
            {
                // do something useful here
            });
        }
    }
}

public class NotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void SetProperty<T>(Expression<Func<T>> propExpr, Expression<Func<T>> fieldExpr, T value)
    {
        SetProperty(propExpr, fieldExpr, value, () => { });
    }

    protected void SetProperty<T>(Expression<Func<T>> propExpr, Expression<Func<T>> fieldExpr, T value, Action doIfChanged)
    {
        var prop = (PropertyInfo)((MemberExpression)propExpr.Body).Member;
        var field = (FieldInfo)((MemberExpression)fieldExpr.Body).Member;

        var currVal = prop.GetValue(this, null);

        if (currVal == null && value == null)
            return;
        if (currVal == null || !currVal.Equals(value))
        {
            field.SetValue(this, value);
            doIfChanged();

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop.Name));
        }
    }
}